package ma.moliere.presentation.controleur;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.servlet.http.HttpServletResponse;

import ma.moliere.domaine.IEleveDomaine;
import ma.moliere.domaine.IGestionDesNotesDomaine;
import ma.moliere.domaine.IGestionInscriptionDomaine;
import ma.moliere.domaine.IParametrage;
import ma.moliere.editique.IGenerateurImpression;
import ma.moliere.persistance.oe.Anneescolaire;
import ma.moliere.persistance.oe.Groupe;
import ma.moliere.persistance.oe.Inscription;
import ma.moliere.presentation.modele.GestionSaisieModele;
import ma.moliere.transverse.Constantes;
import ma.moliere.transverse.utils.NullSafeBeanComparator;
import ma.moliere.transverse.vo.ClasseAffichee;
import ma.moliere.transverse.vo.EleveAffiche;
import ma.moliere.transverse.vo.Mensualite;
import ma.moliere.transverse.vo.NotessaisienormalePremiereAffichee;
import ma.moliere.transverse.vo.ReglementAffiche;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperPrint;

import org.apache.commons.collections.CollectionUtils;
import org.richfaces.log.LogFactory;
import org.richfaces.log.Logger;

/**
 * Le controleur GestionDesSaisiesControleur permet de gérer les actions liées aux saisies.
 * 
 * @author SASMAMI
 * 
 */
public class GestionDesSaisiesControleur implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -32698899528011731L;
	private static Logger LOGGER = LogFactory.getLogger(GestionDesSaisiesControleur.class);

	/**
	 * Constructeur par défaut.
	 */
	public GestionDesSaisiesControleur() {

	}

	/** Injection pour l'accès au modele. */
	private GestionSaisieModele modele;
	/** Injection pour l'accès au domaine pour la gestion des notes. */
	private IGestionDesNotesDomaine noteDomaine;
	/** Injection pour l'accès au domaine pour la gestion des paramétrages. */
	private IParametrage parametrageDomaine;
	/** Injection pour l'accès au domaine pour la gestion des inscriptions. */
	private IGestionInscriptionDomaine inscriptionDomaine;
	/** Injection pour l'accès au domaine pour la gestion des élèves. */
	private IEleveDomaine eleveDomaine;
	private IGenerateurImpression editique;

	public GestionSaisieModele getModele() {
		if (null == modele) {
			modele = new GestionSaisieModele();
		}
		return modele;
	}

	public void setModele(final GestionSaisieModele modele) {
		this.modele = modele;
	}

	public IParametrage getParametrageDomaine() {
		return parametrageDomaine;
	}

	public void setParametrageDomaine(final IParametrage parametrageDomaine) {
		this.parametrageDomaine = parametrageDomaine;
	}

	public IGestionInscriptionDomaine getInscriptionDomaine() {
		return inscriptionDomaine;
	}

	public void setInscriptionDomaine(final IGestionInscriptionDomaine inscriptionDomaine) {
		this.inscriptionDomaine = inscriptionDomaine;
	}

	public String afficherEcranSaisieNotes() {
		getModele().getAnnesScolairesItems().clear();
		getModele().getClassesItems().clear();
		getModele().getGroupesItems().clear();
		// chargement des années scolaire et des classes
		List < Anneescolaire > annees = new ArrayList < Anneescolaire >();
		List < ClasseAffichee > classes = new ArrayList < ClasseAffichee >();
		annees = parametrageDomaine.rechercherAnnees();
		classes = parametrageDomaine.rechercherClasses();
		if (annees != null && !annees.isEmpty()) {
			SelectItem item = null;
			for (Anneescolaire annee : annees) {
				item = new SelectItem();
				item.setLabel(annee.getLibelle());
				item.setValue(annee.getId());
				getModele().getAnnesScolairesItems().add(item);
			}
		} else {
			// Ajouter message d'erreur.
			// rester sur la meme page
		}
		// chargement des classes
		if (classes != null && !classes.isEmpty()) {
			SelectItem item = null;
			for (ClasseAffichee classe : classes) {
				item = new SelectItem();
				item.setLabel(classe.getLibelle());
				item.setValue(classe.getId());
				getModele().getClassesItems().add(item);
			}
		} else {
			// Ajouter message d'erreur.
			// rester sur la meme page
		}

		return "ECR_SAISIE_NOTES";
	}

	@SuppressWarnings(Constantes.UNCHECKED)
	public void chargerGroupe(final ValueChangeEvent event) {
		if (null != event.getNewValue()) {
			Long idClasse = (Long) event.getNewValue();
			List < Groupe > groupes = new ArrayList < Groupe >();
			groupes = parametrageDomaine.rechercherGroupePardIdClasse(idClasse);
			if (CollectionUtils.isNotEmpty(groupes)) {
				getModele().getGroupesItems().clear();
				SelectItem item = null;
				for (Groupe grp : groupes) {
					item = new SelectItem();
					item.setLabel(grp.getLibelle());
					item.setValue(grp.getId());
					getModele().getGroupesItems().add(item);
				}
				Collections.sort(getModele().getGroupesItems(), new NullSafeBeanComparator("libelle"));
			}
		} else {
			getModele().getGroupesItems().clear();
		}
	}

	public String chargerNotes() {

		List < Long > idsgrp = new ArrayList < Long >();
		List < Long > idsAnnee = new ArrayList < Long >();
		List < Long > idsClasse = new ArrayList < Long >();
		idsgrp.add(getModele().getIdGroupe());
		idsClasse.add(getModele().getIdClasse());
		idsAnnee.add(getModele().getIdAnneeScolaire());
		getModele().getNotesPremieres().clear();
		List < NotessaisienormalePremiereAffichee > notes = noteDomaine.rechercherNotesPremiere(getModele().getIdAnneeScolaire(),
			getModele().getIdClasse(), getModele().getIdGroupe(), getModele().getSemestre(), getModele().getEvaluation());
		if (CollectionUtils.isEmpty(notes)) {
			List < Inscription > inscriptions = inscriptionDomaine.rechercherInscriptionParClasseGrpsEtAnnees(idsClasse, idsgrp,
				idsAnnee);
			if (CollectionUtils.isNotEmpty(inscriptions)) {
				NotessaisienormalePremiereAffichee notespremiere = null;
				for (Inscription insc : inscriptions) {
					notespremiere = new NotessaisienormalePremiereAffichee();
					notespremiere.setAnneescolaire(getModele().getIdClasse());
					notespremiere.setClasse(getModele().getIdClasse().toString());
					notespremiere.setGroupe(getModele().getIdGroupe().toString());
					notespremiere.setSemestre(getModele().getSemestre());
					notespremiere.setEvaluation(getModele().getEvaluation());
					notespremiere.setDatesaisie(Calendar.getInstance().getTime());
					// TODO changer le type du matricule.
					notespremiere.setMatricule(Long.valueOf(insc.getMatricule()));
					notespremiere.setNom(insc.getNomeleve());
					notespremiere.setPrenom(insc.getPrenomeleve());
					noteDomaine.ajouterNotePremiere(notespremiere);
					getModele().getNotesPremieres().add(notespremiere);
				}
			}
		} else {
			getModele().getNotesPremieres().addAll(notes);
		}
		return null;
	}

	public String enregistrerNotes() {
		for (NotessaisienormalePremiereAffichee note : getModele().getNotesPremieres()) {
			noteDomaine.modifierNotePremiere(note);
		}
		return null;
	}

	public String afficherEcranSaisirReglement() {
		getModele().getAnnesScolairesItems().clear();
		getModele().getEleves().clear();
		getModele().setAnneescolaire(null);
		getModele().setCritere(null);
		getModele().setAffichePanelCheque(false);
		getModele().getIdsreglementvalides().clear();
		if (getModele().getEleve().getMatricule() != null && !getModele().getEleve().getMatricule().isEmpty()) {
			getModele().getCritere().setMatricule(getModele().getEleve().getMatricule());
		}
		List < Anneescolaire > annees = new ArrayList < Anneescolaire >();
		annees = parametrageDomaine.rechercherAnnees();
		if (annees != null && !annees.isEmpty()) {
			SelectItem item = null;
			for (Anneescolaire annee : annees) {
				item = new SelectItem();
				item.setLabel(annee.getLibelle());
				item.setValue(annee.getId());
				getModele().getAnnesScolairesItems().add(item);
			}
		} else {
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
				"Erreur: La liste des années scolaires n'a pas pu être intialisée.", null);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, facesMsg);
		}
		return "ECR_SAISIE_REGLEMENT";
	}

	@SuppressWarnings(Constantes.UNCHECKED)
	public String lancerRechercherEleve() {
		getModele().getEleves().clear();
		getModele().getReglementsAffiches().clear();
		getModele().getReglements().clear();
		getModele().setAffichePanelCheque(false);
		getModele().getIdsreglementvalides().clear();

		List < EleveAffiche > eleves = eleveDomaine.rechercher(getModele().getCritere());
		getModele().getEleves().addAll(eleves);
		Collections.sort(getModele().getEleves(), new NullSafeBeanComparator("id"));
		return afficherReglements();
	}

	public String afficherReglements() {
		getModele().getMensualites().clear();
		List < String > naturesMensualites = Arrays.asList(Constantes.LISTE_NATURE_MENSUALITES.split(","));
		Mensualite mensualite = null;
		for (String nature : naturesMensualites) {
			mensualite = new Mensualite();
			mensualite.setNature(nature);
			mensualite.setSeleted(false);
			getModele().getMensualites().add(mensualite);
		}

		return null;
	}

	public String changerOption() {
		getModele().setModificationFlag(true);

		if (getModele().getReglement().getTransport().equals("Oui")) {
			getModele().setTransportModification("1");
		} else {
			getModele().setTransportModification("0");
		}

		if (getModele().getReglement().getGarderie().equals("Oui")) {
			getModele().setGarderieModification("1");
		} else {
			getModele().setGarderieModification("0");
		}

		return null;
	}

	public String validerModificationReglement() {
		// // on annule le transport
		// if (getModele().getTransportModification().equals("0")) {
		// getModele().getReglement().setTransport("Non");
		// } else if (getModele().getReglement().getTransport().equals(anObject) == 0) {
		// getModele().getReglement().setTransport(Double.valueOf("500"));
		// }
		//
		// if (getModele().getInfoModification().equals("0")) {
		// getModele().getReglement().setInformatique(Double.valueOf(0));
		// } else if (getModele().getReglement().getInformatique() == 0) {
		// getModele().getReglement().setInformatique(Double.valueOf("400"));
		// }
		//
		// if (getModele().getGarderieModification().equals("0")) {
		// getModele().getReglement().setGarderie(Double.valueOf(0));
		// } else if (getModele().getReglement().getGarderie() == 0) {
		// getModele().getReglement().setGarderie(Double.valueOf("300"));
		// }
		//
		// inscriptionDomaine.modifierReglement(getModele().getReglement());
		// getModele().setModificationFlag(false);
		return null;
	}

	public String validerReglement() {
		getModele().getIdsreglementvalides().clear();
		Double montantdu = Double.valueOf(0);
		List < String > matriculesEleves = new ArrayList < String >();
		List < String > mensualites = new ArrayList < String >();
		List < Long > idsinscription = new ArrayList < Long >();
		for (EleveAffiche eleve : getModele().getEleves()) {
			if (eleve.getFlag()) {
				matriculesEleves.add(eleve.getMatricule());
			}
		}
		for (Mensualite mensualite : getModele().getMensualites()) {
			if (mensualite.getSeleted()) {
				mensualites.add(mensualite.getNature());
			}
		}
		if (CollectionUtils.isEmpty(matriculesEleves) || CollectionUtils.isEmpty(mensualites)) {
			// message d'erreur.
			LOGGER.error("Aucun eleve ou mensualité n'a été séléctionné");
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
				"Aucun élève n'a été séléctionné ou aucune mensualité n'a été séléctionnée.", null);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, facesMsg);
			return null;
		}
		List < Inscription > inscriptions = inscriptionDomaine.rechercherInscription(matriculesEleves, getModele()
			.getIdAnneeScolaire());
		if (CollectionUtils.isNotEmpty(inscriptions)) {
			for (Inscription insc : inscriptions) {
				idsinscription.add(insc.getId());
			}
			List < ReglementAffiche > reglements = inscriptionDomaine.rechercherReglementsParInscription(idsinscription);
			List < String > mensualitesSelectionnees = new ArrayList < String >();
			List < ReglementAffiche > reglementsSelectionnees = new ArrayList < ReglementAffiche >();
			for (Mensualite mensualite : getModele().getMensualites()) {
				if (mensualite.getSeleted()) {
					mensualitesSelectionnees.add(mensualite.getNature());
				}

			}
			if (CollectionUtils.isNotEmpty(reglements)) {
				for (ReglementAffiche reg : reglements) {
					if (mensualitesSelectionnees.contains(reg.getNature())) {
						reglementsSelectionnees.add(reg);
					}
				}
				if (getModele().getModePaiement().equals(Constantes.PAIEMENT_PAR_CHEQUE)) {
					for (ReglementAffiche reg : reglementsSelectionnees) {
						montantdu += reg.getMontant();
					}
					if (montantdu.doubleValue() != getModele().getMontantcheque().doubleValue()) {
						LOGGER.error("Montant du chèque ne correspond pas au montant du.");
						FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Montant du chèque ne correspond pas au montant du qui s'élève à  " + montantdu + "DH", null);
						FacesContext context = FacesContext.getCurrentInstance();
						context.addMessage(null, facesMsg);
						return null;
					} else {
						for (ReglementAffiche reg : reglementsSelectionnees) {
							reg.setDatereglement(Calendar.getInstance().getTime());
							reg.setModepaiement(Constantes.PAIEMENT_PAR_CHEQUE);
							reg.setNumcheque(getModele().getNumerocheque());
							reg.setDatecheque(Calendar.getInstance().getTime());
							reg.setEmetteurcheque(getModele().getProprietairecheque());
							reg.setBanque(getModele().getBanque());
							inscriptionDomaine.modifierReglement(reg);
							getModele().getIdsreglementvalides().add(reg.getId());
						}
					}
				} else {
					for (ReglementAffiche reg : reglementsSelectionnees) {
						reg.setDatereglement(Calendar.getInstance().getTime());
						reg.setModepaiement(Constantes.PAIEMENT_PAR_ESPECE);
						inscriptionDomaine.modifierReglement(reg);
						getModele().getIdsreglementvalides().add(reg.getId());
					}
				}

			}
		} else {
			LOGGER.error("Aucun eleve ou mensualité n'a été séléctionner");
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
				"La recherche des réglement n'a pas pas abouti.", null);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, facesMsg);
			return null;
		}

		FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "La transaction a été validée avec succès.", null);
		FacesContext context = FacesContext.getCurrentInstance();
		context.addMessage(null, facesMsg);
		getModele().getEleves().clear();
		getModele().getMensualites().clear();
		getModele().setAffichePanelCheque(false);
		return null;
	}

	public void valueChanged(final ValueChangeEvent event) {
		if (null != event.getNewValue()) {

			if (((String) event.getNewValue()).equals("cheque")) {
				getModele().setAffichePanelCheque(true);
			} else {
				getModele().setAffichePanelCheque(false);
			}

		}
	}

	public void afficherAutre(final ValueChangeEvent event) {
		if (null != event.getNewValue()) {
			if (((String) event.getNewValue()).equals("AUTRE")) {
				getModele().setAfficherAutre(true);
			} else {
				getModele().setAfficherAutre(false);
			}
		}
	}

	public String enregisterAbsence() {
		if (getModele().getAbsence().getId() == null) {
			getModele().getAbsence().setAnneescolaire(getModele().getIdAnneeScolaire());
			getModele().getAbsence().setDatedeclaration(Calendar.getInstance().getTime());
			getModele().getAbsence().setMatricule(getModele().getEleve().getMatricule());
			getModele().getAbsence().setNom(getModele().getEleve().getNom());
			getModele().getAbsence().setPrenom(getModele().getEleve().getPrenom());
			if (getModele().getAbsence().getDatedebutabsence().compareTo(getModele().getAbsence().getDatefinabsence()) > 0) {
				FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
					"La date de début d'absence doit être antérieure à la date de fin d'asence.", null);
				FacesContext context = FacesContext.getCurrentInstance();
				context.addMessage(null, facesMsg);

			}
			eleveDomaine.ajouter(getModele().getAbsence());
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Absence enregistrée avec succès.", null);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, facesMsg);
		} else {
			eleveDomaine.modifier(getModele().getAbsence());
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Absence modifiée avec succès.", null);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, facesMsg);
		}
		getModele().setAbsence(null);
		return null;
	}

	public String imprimerRecu() {
		try {
			FacesContext context = FacesContext.getCurrentInstance();
			ExternalContext ext = context.getExternalContext();
			HttpServletResponse resp = (HttpServletResponse) ext.getResponse();
			resp.setContentType("application/pdf");
			resp.addHeader("Content-Disposition", "inline; filename=recu");
			JasperPrint jasperPrint = editique.genererRecuPaiement(getModele().getIdsreglementvalides());
			JasperExportManager.exportReportToPdfStream(jasperPrint, resp.getOutputStream());
			context.getApplication().getStateManager().saveView(context);
			context.responseComplete();
		} catch (Exception e) {

			LOGGER.error(e);
			FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "La génération du reçu a échoué", null);
			FacesContext context = FacesContext.getCurrentInstance();
			context.addMessage(null, facesMsg);

		}
		return null;
	}

	/**
	 * Accesseur en ecriture pour l'attribut noteDomaine.
	 * 
	 * @return IGestionDesNotesDomaine.
	 */
	public final IGestionDesNotesDomaine getNoteDomaine() {
		return noteDomaine;
	}

	/**
	 * Accesseur en ecriture pour l'attribut noteDomaine.
	 * 
	 * @param noteDomaine
	 *            : param.
	 */
	public final void setNoteDomaine(final IGestionDesNotesDomaine noteDomaine) {
		this.noteDomaine = noteDomaine;
	}

	/**
	 * Accesseur en ecriture pour l'attribut eleveDomaine.
	 * 
	 * @return IEleveDomaine.
	 */
	public final IEleveDomaine getEleveDomaine() {
		return eleveDomaine;
	}

	/**
	 * @param eleveDomaine
	 *            the eleveDomaine to set
	 */
	public void setEleveDomaine(final IEleveDomaine eleveDomaine) {
		this.eleveDomaine = eleveDomaine;
	}

	/**
	 * Accesseur en ecriture pour l'attribut editique
	 */
	public void setEditique(final IGenerateurImpression editique) {
		this.editique = editique;
	}

}
